/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package net.worlds.object;

import java.awt.Color;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.worlds.WorldsException;
import net.worlds.Main;
import net.worlds.PropChangeHandler;
import net.worlds.TraceResult;
import net.worlds.ui.UI;
import org.jbox2d.common.Vec2D;
import se.krka.kahlua.vm.JavaFunction;
import se.krka.kahlua.vm.LuaCallFrame;


public class World extends Model{
    public World() throws WorldsException
    {
        super("World");
        addPropChangeHandler("Size", new PropChangeHandler()
        {
            @Override
            public void handle(Object oldValue, final Object value) throws WorldsException {
                addAction(new Runnable()
                {
                    Vec2D vec = (Vec2D) value;
                    public void run() {
                        if(!(vec.x == 0 && vec.y == 0))
                            try {
                            world.setSize(vec.x, vec.y);
                        } catch (WorldsException ex) {
                            ex.printStackTrace();
                        }
                    }

                });
            }

        });
        addPropChangeHandler("Gravity", new PropChangeHandler()
        {
            @Override
            public void handle(Object oldValue, final Object value) throws WorldsException {
                addAction(new Runnable()
                {
                    Vec2D vec = (Vec2D) value;
                    public void run() {
                        world.setGravity(vec);
                    }

                });
            }
        });
        addPropChangeHandler("BackgroundColor", new PropChangeHandler()
        {

            @Override
            public void handle(Object oldValue, Object value) throws WorldsException {
                world.setBackgroundColor((Color) value);
            }

        });
        addPropChangeHandler("BackgroundImage", new PropChangeHandler()
        {

            @Override
            public void handle(Object oldValue, Object value) throws WorldsException {
                world.setBackgroundImage(value.toString());
                if(!Main.noView && !value.equals("") && world == Main.getGame().getCurrentWorld() && !Main.loading)
                {
                    if(world.scaleBackground)
                        Main.getView().updateBackground();
                    else
                        Main.getView().updatePaint(world);
                }
            }

        });
        addPropChangeHandler("ScaleBackground", new PropChangeHandler()
        {

            @Override
            public void handle(Object oldValue, Object value) throws WorldsException {
                world.scaleBackground = (Boolean) value;
                if(!Main.noView && world.getBackgroundImage() != null && world == Main.getGame().getCurrentWorld() && !Main.loading)
                {
                    if(world.scaleBackground)
                        Main.getView().updateBackground();
                    else
                        Main.getView().updatePaint(world);
                }
            }

        });
        addPropChangeHandler("ScrollBackground", new PropChangeHandler()
        {

            @Override
            public void handle(Object oldValue, Object value) throws WorldsException {
                world.scrollBackground = (Boolean) value;
            }

        });
        addPropChangeHandler("TimeScale", new PropChangeHandler()
        {

            @Override
            public void handle(final Object oldValue, final Object value) {
                world.setTimescale((Float) value);
            }
        });
        addPropChangeHandler("PhysicsAccuracy", new PropChangeHandler()
        {
            @Override
            public void handle(final Object oldValue, final Object value) {
                world.physicsAccuracy = (Integer) value;
            }
        });
        //x_;
        addFunction("getPartAt", new JavaFunction()
        {

            public int call(LuaCallFrame callFrame, int nArguments) {
                if(nArguments != 2 || !(callFrame.get(1) instanceof Vec2D))
                    throw new RuntimeException("Argument to getPartAt() must be a Vec2D");
                Vec2D vec = (Vec2D) callFrame.get(1);
                Part p = getPartAt(vec);
                if(p == null)
                    callFrame.pushNil();
                else
                    callFrame.push(p);
                return 1;
            }
        });
        addFunction("makeWeld", new JavaFunction()
        {
            public int call(LuaCallFrame callFrame, int nArguments) {
                if(nArguments != 2 || !(callFrame.get(1) instanceof Vec2D))
                    throw new RuntimeException("Argument to getPartAt() must be a Vec2D");
                final Vec2D vec = (Vec2D) callFrame.get(1);
                Main.runInMainThread(new Runnable()
                {
                    public void run() {
                        try {
                            int oldMouseMode = UI.mouseMode;
                            UI.mouseMode = UI.MODE_WELD;
                            UI.makeJoint(vec);
                            UI.mouseMode = oldMouseMode;
                        } catch (WorldsException ex) {
                            ex.printStackTrace();
                        }
                    }
                });
                return 0;
            }
        });
        addFunction("makeHinge", new JavaFunction()
        {
            public int call(LuaCallFrame callFrame, int nArguments) {
                if(nArguments != 2 || !(callFrame.get(1) instanceof Vec2D))
                    throw new RuntimeException("Argument to getPartAt() must be a Vec2D");
                final Vec2D vec = (Vec2D) callFrame.get(1);
                Main.runInMainThread(new Runnable()
                {
                    public void run() {
                        try {
                            int oldMouseMode = UI.mouseMode;
                            UI.mouseMode = UI.MODE_HINGE;
                            UI.makeJoint(vec);
                            UI.mouseMode = oldMouseMode;
                        } catch (WorldsException ex) {
                            ex.printStackTrace();
                        }
                    }
                });
                return 0;
            }
        });
        addFunction("getTrace", new JavaFunction()
        {
            public int call(LuaCallFrame callFrame, int nArguments) {
                if(nArguments == 3 && callFrame.get(1) != null && callFrame.get(1) instanceof Vec2D && callFrame.get(2) != null && callFrame.get(2) instanceof Double)
                {
                    Vec2D pos = (Vec2D) callFrame.get(1);
                    double angle = (Double) callFrame.get(2);
                    Vec2D unit = new Vec2D(Math.toRadians(angle));
                    TraceResult r = world.getTrace(pos, unit, null);
                    if(r == null)
                        callFrame.pushNil();
                    else
                        callFrame.push(r);
                    return 1;
                }
                throw new RuntimeException("getTrace() requires a Vec2D and a number");
            }
        });
    }
    public Part getPartAt(Vec2D pos)
    {
        for(int i = 2; i >= 0; i--)
        {
            List<GameObject> layer = world.getLayer(i);
            synchronized(layer)
            {
                for(int j = layer.size() - 1; j >= 0; j--)
                {
                    GameObject obj = layer.get(j);
                    if(!(obj instanceof Part))
                        continue;
                    try {
                        Part p = (Part) obj;
                        if (!obj.disabled && obj != null && !obj.getBooleanProp("Locked") && p.getShape() != null && p.getShape().testPoint(p.getBody().getXForm(), pos)) {
                            return p;
                        }
                    } catch (WorldsException ex) {
                        throw new RuntimeException(ex);
                    }
                }
            }
        }
        return null;
    }

    @Override
    public void addToWorld() throws WorldsException
    {
        super.addToWorld();
        if(Main.getGame().type != 0)
        {
            setProp("Gravity", Vec2D.ORIGIN, true);
        }
    }
}
